package com.atguigu.hive.function;

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.StructField;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.json.JSONArray;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

//一.继承 GenericUDTF类，实现initialize, process,选择性实现close
public class ExplodeJsonArray extends GenericUDTF {
//二.initialize 被hive调用用来验证函数入参类型是否合法,返回值必须返回UDTF函数生成的每行内容对应的object inspector(可能每行有多列)
    @Override
    public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
        //2.1 将函数的入参参数封装为一个StructObjectInspector对象,argOIs表示函数的参数列表
           // 这里函数的入参类型应该是jsonArray字符串,只有一列,只有一个对象
        //2.2 获取参数列表
        List<? extends StructField> inputFields = argOIs.getAllStructFieldRefs();
        //2.3 判断参数个数是不是仅有一个,如果不是就抛异常
        if(inputFields.size()!=1){
            throw new UDFArgumentLengthException("要求传入的参数必须只能是1个!");
        }
        //2.4 判断参数类型是不是string,如果不是就抛异常(注意必须为hive识别的类型'string',只能小写)
        if(!"string".equals(inputFields.get(0).getFieldObjectInspector().getTypeName())){
            throw new UDFArgumentException("要求传入的参数类型必须只能是string!");
        }
        //2.5 返回结果应该是object inspector (1列string)
            //2.5.1 返回的每行每列字段的别名,可能有多列,所以用数组
        ArrayList<String> fieldNames = new ArrayList<String>();
            //2.5.2 返回的每行每列字段的object inspector,可能有多列,所以用数组
        ArrayList<ObjectInspector> fieldOIs = new ArrayList<ObjectInspector>();
        fieldNames.add("singlejsonAction");
            //2.5.3 使用对象检查器工厂类得到标准的ObjectInspector
        fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames,
                fieldOIs);
    }
    //输出的每行只有1列
    Object outputLine []=new Object[1];
    //三.当initialize 被调用后，函数传入的一行数据，会经过process()进行处理，之后调用forward以行为单位写出
    // Object[] args就是写入函数的参数
    @Override
    public void process(Object[] args) throws HiveException {
        String jsonArray = args[0].toString();
        //3.1通过json工具类将string转成jsonArray的java对象
        JSONArray jsonArray1 = new JSONArray(jsonArray);
        for (int i = 0; i < jsonArray1.length(); i++) {
            //3.2取出一行中每个jsonobject,这个jsonobject为一列
            JSONObject jsonObject = jsonArray1.getJSONObject(i);
            //3.3将jsonobject转为字符串以行为单位写出
            //一行为单位写出
            outputLine[0] =  jsonObject.toString();
            forward(outputLine);
        }
    }
    //4. 在数据处理完后调用,执行一些清理操作
    @Override
    public void close() throws HiveException {

    }

}
